package com.example.quartzdemo.context;

import lombok.extern.log4j.Log4j2;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 定时任务管理器
 * @author hezhongying
 * @create 2024/12/11
 */
@Configuration
@Log4j2
public class QuartzManager {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private List<Job> taskList;

    private Map<String, Job> taskMap;

    @PostConstruct
    public void init() {
        this.taskMap = taskList.stream().collect(Collectors.toMap(t -> t.getClass().getSimpleName(), t -> t));
    }

    /**
     * 启动任务
     * @param jobName 任务名
     * @param group 组名
     * @param cron cron表达式
     * @throws SchedulerException
     */
    public void startJobTask(String jobName, String group, String cron) throws SchedulerException {
        // 创建Job
        JobKey jobKey = new JobKey(jobName, group);

        // 判断任务是否已存在，不存在新增，存在更新
        if (scheduler.checkExists(jobKey)) {
            if (modifyJob(jobName, group, cron)) {
                log.info("任务：{} 修改成功", jobName);
            }
        } else {
            if (createJob(jobName, group, cron)) {
                log.info("任务：{} 新增成功", jobName);
            }
        }
    }

    /**
     * 新增任务
     * @param jobName 任务名称
     * @param group 分组
     * @param cron CRON表达式
     * @throws SchedulerException
     */
    private boolean createJob(String jobName, String group, String cron) throws SchedulerException {
        // 任务新增
        if (taskMap.containsKey(jobName)) {
            // 执行任务
            Class<? extends Job> taskClazz = taskMap.get(jobName).getClass();
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("jobName", "param");
            JobDetail jobDetail = JobBuilder.newJob(taskClazz)
                    .withIdentity(jobName, group)
                    .usingJobData(jobDataMap)
                    .build();

            // 执行时间corn表达式
            CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule(cron);
            CronTrigger cronTrigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(jobName, group)
                    .withSchedule(cronBuilder)
                    .build();

            scheduler.scheduleJob(jobDetail, cronTrigger);
            return true;
        } else {
            log.debug("任务没有配置执行配置{}", jobName);
        }
        return false;
    }

    /**
     * 修改
     *
     * @param jobName 任务名
     * @param group 组名
     * @param cron cron表达式
     * @return true，修改成功；false，修改失败
     * @throws SchedulerException
     */
    public boolean modifyJob(String jobName, String group, String cron) throws SchedulerException {
        TriggerKey triggerKey = new TriggerKey(jobName, group);

        Trigger trigger = scheduler.getTrigger(triggerKey);
        if (trigger == null) {
            log.info("未存在的触发器[{}-{}]", jobName, group);
            return false;
        }

        String oldCron = ((CronTrigger) trigger).getCronExpression();
        // 判断cron是否相等，相等就不用改
        if (!cron.equals(oldCron)) {
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            CronTrigger newTrigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(jobName, group)
                    .withSchedule(cronScheduleBuilder)
                    .build();

            Date date = scheduler.rescheduleJob(triggerKey, newTrigger);
            return date != null;
        } else {
            log.info("任务：{} CRON表达式没有变化", jobName);
        }

        return false;
    }

    /**
     * 暂停所有任务
     *
     * @throws SchedulerException
     */
    public void pauseAll() throws SchedulerException {
        this.scheduler.pauseAll();
    }

    /**
     * 指定任务暂停
     *
     * @param jobName 任务名
     * @param group 组名
     * @throws SchedulerException
     */
    public void pause(String jobName, String group) throws SchedulerException {
        JobKey jobKey = new JobKey(jobName, group);
        JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
        if (jobDetail == null) {
            return;
        }

        this.scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复所有任务
     *
     * @throws SchedulerException
     */
    public void resumeAllJob() throws SchedulerException {
        this.scheduler.resumeAll();
    }

    /**
     * 删除指定任务
     *
     * @param jobName 任务名
     * @param group 组名
     * @throws SchedulerException
     */
    public void delete(String jobName, String group) throws SchedulerException {
        JobKey jobKey = new JobKey(jobName, group);
        JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
        if (jobDetail == null) {
            return;
        }
        this.scheduler.deleteJob(jobKey);
    }
}
